package org.gaelocaltest.ext;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.xml.sax.SAXException;

import com.google.appengine.api.labs.taskqueue.dev.LocalTaskQueue;
import com.google.appengine.api.labs.taskqueue.dev.QueueStateInfo.TaskStateInfo;
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;

/**
 * @author 403rus@gmail.com (Dmitriy T.)
 */
public class TaskRunner {

	/**
	 * Run all tasks in queue (tasks created in process were not run)
	 * If some tasks return not 2xx status - they not deleted from queue
	 * 
	 * @param queueName
	 * @param servInstance - servlet instance for task 
	 * @return number succeed runned tasks
	 */
	public static <T extends HttpServlet> int runTasksInQueue(String queueName, T servInstance)
			throws IOException, SAXException, SecurityException, NoSuchMethodException,
			IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		int ret;
		
		ArrayList<String> tasksToDel = new ArrayList<String>();

		LocalTaskQueue ltq = LocalTaskQueueTestConfig.getLocalTaskQueue();

		MockHttpServletRequest request = new MockHttpServletRequest();
		MockHttpServletResponse response = new MockHttpServletResponse();
		ret = 0;
		
		List<TaskStateInfo> taskList = new ArrayList<TaskStateInfo>();
		
		// for prevent comodification get taskList before run tasks
		// maybe its not necessary
		for (TaskStateInfo taskInfo : ltq.getQueueStateInfo().get(queueName).getTaskInfo()) {
			taskList.add(taskInfo);
		}
		
		for (TaskStateInfo info : taskList) {//ltq.getQueueStateInfo().get(queueName).getTaskInfo()) {
			String s3;
			Method meth;
			Class partypes[] = new Class[2];

			partypes[0] = HttpServletRequest.class;
			partypes[1] = HttpServletResponse.class;

			request = new MockHttpServletRequest();
			response = new MockHttpServletResponse();
			if (info.getMethod().equals("POST")) {
				s3 = "?" + URLDecoder.decode(info.getBody(), "UTF8");
				meth = servInstance.getClass().getMethod("doPost", partypes);
			} else {
				s3 = URLDecoder.decode(info.getUrl(), "UTF8");
				meth = servInstance.getClass().getMethod("doGet", partypes);
			}

			if (s3.indexOf('?') != -1) {
				s3 = s3.substring(s3.indexOf('?') + 1);
				String params[];
				params = s3.split("&");
				HashMap<String, String> reqParams;
				reqParams = new HashMap<String, String>();
				for (String curp : params) {
					reqParams.put(curp.substring(0, curp.indexOf('=')),
							curp.substring(curp.indexOf('=') + 1));
				}
				for (String pn : reqParams.keySet()) {
					request.setParameter(pn, reqParams.get(pn));
				}
			}

			try {
				meth.invoke(servInstance, HttpServletRequest.class.cast(request),
						HttpServletResponse.class.cast(response));
				++ret;
			} catch (InvocationTargetException e) {
				response.setStatus(500);
			}
			
			if (response.getStatus() >= 200 && response.getStatus() <= 299) {
				tasksToDel.add(info.getTaskName());
			}
		}

		for (String tn : tasksToDel) {
			ltq.deleteTask(queueName, tn);			
		}

		return ret;
	}

}
